import java.io.IOException;

import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;


public class seMueve extends MIDlet implements CommandListener {
	
	/**
	*Atributos
	*/
	private Display display;
	private Command exit, menu, back,okl,ins,guardar,okb,run;
	private List opciones, idioma,agregar,mapasDisp, opciones1;
	private Displayable actual;
	private String[] language, cosas, instAnt, todasInst, nombres;
	private Mapa mapitas[];
	private	boolean espanol;
	private Mapa mapita;
	private MenuMapa submapa;
	private Form crear;
	private StringItem instrucciones;
	private Command[] comandos;
	private Interprete inter;
	private int nm,me, instAgre, totalInst;
	private String instrucActual;
	

	public seMueve() {
		/** TODO Auto-generated constructor stub
		 *Crea las opciones del menú en español y los comandos
		 */
		totalInst = 1;
		instAgre = 0;
		instAnt = new String[20];
		todasInst = new String[21];
		nombres = new String[21];
		instrucActual = "right()\nright()\nbackward(4)\nright()\nright()\nright()\npickUp()\nright()\nputDown()\nforward(2)\nend";
		todasInst[0] = instrucActual;
		nombres[0] = "Default";
		inter = new Interprete(instrucActual);
		language=new String[20];
		cosas=new String[5];
		espanol=true;
		nm=1;
		me=0;
		mapitas=new Mapa[100];
		mapitas[nm-1]=crearMapa();
		mapitas[nm-1].repaint();
		mapita=mapitas[nm-1];
		cambiarIdioma();
		mapasDisp=new List("", Choice.IMPLICIT);
		mapasDisp.append("Mapa 1", null);
		mapasDisp.setCommandListener(this);
		
		
	}

	protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
	}

	protected void pauseApp() {
		
	}

	protected void startApp() throws MIDletStateChangeException {
		/** 
		 * Revisa si hay algo en actual
		 * si no hay nada coloca como actual a la lista opciones
		 */
		display = Display.getDisplay(this);
		
		if (actual==null)
		{
			display.setCurrent(opciones);
			actual=opciones;
		} else
			display.setCurrent(actual);

	}

	
	/**
	 * Realiza la acción dependiendo del comando que ha sido activado
	 */
	public void commandAction(Command c, Displayable d) {
		
		/**
		 * Si el comando fue exit sale de la aplicacion
		 */
		if(c==exit)
			notifyDestroyed();
		/**
		 * Si el comando fue menu muestra la lista de idioma
		 * actual recibe idioma
		 */
		else if(c==menu){
			actual=idioma;
			display.setCurrent(actual);
		}
		/**
		 * si el comando fue run llama al metodo realizar Instrucciones
		 * hace repaint del mapa
		 */
		else if(c==run){
			realizarInstrucciones();
			mapita.repaint();
		}
		/**
		 * SI el comando fue el de ok de idioma revisa que idioma se selecciono
		 * llama al metodo de cambiar idioma para cambiar todas las labels
		 * Reinicia el mapa contenido en mapitas guardando el mapa escogido
		 * Coloca en display y actual a opciones
		 */
		else if(c==okl)	{
			if(idioma.getSelectedIndex()==0)
				espanol=false;
			else
				espanol=true;
			mapita=mapitas[me];
			cambiarIdioma();
			actual=opciones;
			display.setCurrent(actual);		
		}
		/**
		 *Si el comando fue el de back coloca como actual a opciones
		 *lo muestra en el display 
		 */
		else if(c==back){
			actual=opciones;
			display.setCurrent(actual);
		}
		/**
		 * Si el comando fue el de la seleccion de una lista revisa
		 * que lista fue la que lo llamo
		 */
		else if(c==List.SELECT_COMMAND)
		{
			/**
			 * si el actual es igual a opciones revisa cual es el index
			 * seleccionado en opciones
			 */
			if(actual==opciones)
			{
				int op=opciones.getSelectedIndex();
				switch (op)
				{
				/**
				 * si fue la opcion uno reinicializa el mapita y
				 * lo muestra en el display
				 */
				case 0:
					cambiarIdioma();
					mapita.repaint();
					actual=mapita;
					display.setCurrent(actual);
					break;
					/**
					 * Si fue la opcion dos coloca como actual a crear
					 * y llama al metodo crear codigo
					 */
				case 1:
					crearCodigo();
					actual=crear;
					display.setCurrent(actual);
					break;
					/**
					 * Si fue la opción 3 muestra el menu de mapas
					 */
				case 2:
					actual=mapasDisp;
					display.setCurrent(actual);
					break;
					/**
					 * Si fue la opción 4 llama al método selecInst
					 */
				case 3:
					selecInst();
					break;
					/**
					 * Si fue la opción 5 muestra la pantalla para crear mapas
					 */
				case 4:
					submapa=new MenuMapa(language[12],Choice.IMPLICIT,espanol);
					submapa.addCommand(back);
					submapa.addCommand(guardar);
					submapa.setCommandListener(this);
					actual=submapa;
					display.setCurrent(actual);
					break;
				}
			}
			else
				/**
				 * Si en actual se encontraba el menu de elegir el elemento
				 * de los mapas entonces regresa a la pantalla de crear mapa
				 */
				if (actual==submapa)
				{
					actual=agregar;
					display.setCurrent(actual);
				}
			/**
			 * Si en actual esta mapas Disp entonces le muestra
			 * el menu principal de opciones al usuario.
			 */
				else if(actual==mapasDisp)
				{
					me=mapasDisp.getSelectedIndex();
					actual=opciones;
					display.setCurrent(actual);
				}
		}
		/**
		 * SI el comando fue okb entonces cambia el elemento de la
		 * celda seleccionada en el menu de mapas.
		 */
		else if(c==okb){
			int ele=1;
					
			switch(agregar.getSelectedIndex())
			{
			case 0:
				ele=1;
				break;
			case 1:
				ele=2;
				break;
			case 2:
				ele=3;
				break;
			case 3:
				ele=5;
				break;
			}
			submapa.setElemento(submapa.getSelectedIndex(), ele);
			actual=submapa;
			display.setCurrent(actual);
		}
		/**
		 * Si el comando fue guardar agrega el nuevo mapa al array de mapas
		 * Crea una nueva opción en la lista.
		 */
		else if(c==guardar)
		{
			nm+=1;
			mapitas[nm-1]=new Mapa(submapa.getMatriz());
			mapasDisp.append("Mapa "+Integer.toString(nm), null);
			actual=opciones;
			display.setCurrent(actual);
		}
							
		
	}
	
	/**
	 * Método que crea la lista opciones1 para que el usuario pueda ingresar
	 * las instrucciones en su nuevo código.
	 */
	public void selecInst(){
		opciones1 = new List("Elije el codigo que quieres correr:", Choice.IMPLICIT);
		for (int i=0; i<totalInst ;i++)
			opciones1.append(nombres[i], null);
		opciones1.addCommand(back);
		opciones1.setCommandListener(new ElegirCodigoListener());
		display.setCurrent(opciones1);
	}

	/**
	 * Método que crea mapa predeterminado
	 * @return
	 */
	public Mapa crearMapa()
	{
		int[][] matriz;
		int dimx, dimy;
		
		/**
		 * Inicializa las variables
		 */
		
		dimx=10;
		dimy=10;
		matriz= new int[dimy][dimx];
		
		/**
		 * Coloca piso en toda la matriz
		 * representado por le número 1
		 */
		
		for(int i=0;i<dimy;i++)
			for (int j=0;j<dimx;j++)
				matriz[i][j]=1;
		
		/**
		 * Coloca pared al rededor de la matriz
		 * representado por el número 2
		 */
	
		for(int i=0;i<dimx;i++)
		{
			matriz[0][i]=2;
			matriz[9][i]=2;
		}
		
		for(int i=0;i<dimy;i++)
		{
			matriz[i][0]=2;
			matriz[i][9]=2;
		}
		
		
		/**
		 * Coloca las cajas dentro del mapa
		 * representado por el número 3
		 */
	
		matriz[3][4]=3;
		matriz[4][2]=3;
		matriz[2][1]=3;
		
		
		/**
		 * Coloca en beacon dentro del mapa
		 * representado por el número 5
		 */
		
		matriz[5][6]=5;
		
		/**
		 * Coloca al robot en su posición inicial
		 * representado por el numero 4
		 */
		
		matriz[1][1]=4;
		return( new Mapa(matriz));
		
		

	}
	

	/**
	 * Método que corre las instrucciones que el usuario ha elegido.
	 */
	 public void realizarInstrucciones(){
		 String inst = "";
		 instrucActual = inter.getInstrucciones();
		 while (inst!="true"){
			 if (inst.equals("end")){
				 inst = "true";
			 }
			 else{
				 inst = inter.siguienteInstruccion();
				 if (inst!="true")
					 mapita.identificar(inst);	
			 }
		 }
		 inter.setInstrucciones(instrucActual);
	 }
	
	 /**
	  * Método que cambia el idioma de toda la interfaz
	  */
	public void cambiarIdioma()
	{
		
		Image ic1,ic2,ic3,ic4;
		
		/**
		 * Inicializa las imagenes de uno de los menus
		 */
		ic1=null;
		ic2=null;
		ic3=null;
		ic4=null;
		
		/**
		 * Crea el mapa que se va a utilizar por medio de la matriz
		 */
		mapita=new Mapa(mapitas[me].getMatriz());
		mapitas[me]=mapita;
		
		/**
		 * Si el idioma seleccionado es el español guarda todas las labels
		 * a utilizar en español dentro de un array
		 */
		if(espanol)
		{
			language[0]="Salir";
			language[1]="Idioma";
			language[2]="Regresar";
			language[3]="Elija una opcion";
			language[4]="Empezar";
			language[5]="Cargar Codigo...";
			language[6]="Cargar Mapa...";
			language[7]="Ayuda";
			language[8]="Elija idioma:";
			language[9]="OK";
			language[10]="Insertar";
			language[11]="Elegir Mapa...";
			language[12]="Crear Mapa";
			language[13]="Crear Codigo";
			language[14]="Correr";
			language[15]="Guardar";
			language[16]="Elegir Codigo";
			
			cosas[0]="Grama";
			cosas[1]="Pared";
			cosas[2]="Caja";
			cosas[3]="Beacon";
			
		}
		/**
		 * Si el idioma seleccionado es el inglés guarda todas las labels
		 * a utilizar en inglés dentro de un array
		 */
		else
		{
			language[0]="Exit";
			language[1]="Language";
			language[2]="Back";
			language[3]="Choose an option";
			language[4]="Create";
			language[5]="Load Code...";
			language[6]="Load Map...";
			language[7]="Help";
			language[8]="Choose a language:";
			language[9]="OK";
			language[10]="Insert";
			language[11]="Choose Map...";
			language[12]="Create Map";
			language[13]="Create Code";
			language[14]="Run";
			language[15]="Save";
			language[16]="Choose Code";
			
			cosas[0]="Grass";
			cosas[1]="Wall";
			cosas[2]="Box";
			cosas[3]="Beacon";
			
		}
		
		
		/**
		 * Crea los comandos
		 */

		exit = new Command(language[0], Command.EXIT, 1);
		menu = new Command(language[1], Command.ITEM, 1);
		back=new Command(language[2], Command.BACK, 2);
		okl=new Command(language[9],Command.OK,0);
		ins=new Command(language[10],Command.ITEM,3);
		okb=new Command(language[9],Command.OK,0);
		guardar=new Command(language[15], Command.ITEM,2);
		run=new Command(language[14],Command.ITEM,1);
		
		/**
		 * Crea las lista del menu principal
		 */

		opciones=new List(language[3], Choice.IMPLICIT);
		opciones.append(language[4], null);
		opciones.append(language[13], null);
		opciones.append(language[11], null);
		opciones.append(language[16], null);
		opciones.append(language[12], null);
		opciones.append(language[7], null);
		
		
		/**
		 * Crea el menu de idioma
		 */
	
		idioma=new List(language[8], Choice.EXCLUSIVE);
		idioma.append("English", null);
		idioma.append("Espa�ol", null);
		
		/**
		 * Crea el menu de mapa nuevo
		 */
		
		
		/**
		 * Intenta crear las imagenes del menu
		 */
		try {
			ic1=Image.createImage("/grama.jpg");
			ic2=Image.createImage("/pared.jpg");
			ic3=Image.createImage("/caja.jpg");
			ic4=Image.createImage("/beacon.png");
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		agregar=new List("",Choice.EXCLUSIVE);;
		agregar.append(cosas[0], ic1);
		agregar.append(cosas[1], ic2);
		agregar.append(cosas[2], ic3);
		agregar.append(cosas[3], ic4);
		agregar.addCommand(okb);
		agregar.setCommandListener(this);
		
		
		
		/**
		 * Agrega los comandos y listeners al menu principal
		 * Lugo agrega los comandos y listeners al mapa
		 */
		
		opciones.addCommand(menu);
		opciones.addCommand(exit);
		opciones.setCommandListener(this);
		
		mapita.addCommand(back);
		mapita.addCommand(run);
		mapita.setCommandListener(this);
		
		idioma.addCommand(okl);
		idioma.setCommandListener(this);
		
			
	}
	
	/**
	 * Método que inserta una instrucción en el StringItem
	 * @param inst
	 * @param veces
	 */
	public void insertarInstruccion(int inst, int veces){
		String[] instruc={"forward(","backward(","left()\n","right()\n","pickUp()\n","putDown()\n","end"};
		String anteriores = instrucciones.getText();
		instAnt[instAgre] = anteriores;
		instAgre++;
		if (inst == 2 | inst == 3)
			instrucciones.setText(anteriores+instruc[inst-2]+veces+")\n");
		else
			instrucciones.setText(anteriores+instruc[inst-2]);
	}
	
	/**
	 * Método que inicializa el form para que el usuario pueda
	 * ingresar las instrucciones
	 */
	public void crearCodigo(){
		comandos = new Command[8];
		/**
		 * Coloca las labels de los comandos dependiendo del idioma en el
		 * que se este trabajando.
		 */
		if (espanol){
			crear = new Form("Crear Codigo");
			instrucciones = new StringItem("Inserta la instruccion que quieras:\n","");
			comandos[0] = new Command("Regresar", Command.EXIT, 0);
			comandos[1] = new Command("Quitar", Command.ITEM, 1);
		}
		else{
			crear = new Form("Create Code");
			instrucciones = new StringItem("Insert the desired instruction:\n","");
			comandos[0] = new Command("Back", Command.ITEM, 0);
			comandos[1] = new Command("Remove", Command.ITEM, 1);
		}
		/**
		 * Llena los demas items del menu con las instrucciones
		 * que el usuario puede elegir
		 */
		comandos[2] = new Command("forward(x)", Command.ITEM, 2);
		comandos[3] = new Command("backward(x)", Command.ITEM, 3);
		comandos[4] = new Command("left()", Command.ITEM, 4);
		comandos[5] = new Command("right()", Command.ITEM, 5);
		comandos[6] = new Command("pickUp()", Command.ITEM, 6);
		comandos[7] = new Command("putDown()", Command.ITEM, 7);
		for (int i = 0; i < 8; i++)
			crear.addCommand(comandos[i]);
		crear.append(instrucciones);
		crear.setCommandListener(new CrearCodigoListener());
	}

	/**Clase listener que permite elegir el codigo deseado para que se corra posteriormente 
	 */
	private class ElegirCodigoListener implements CommandListener{
		
		/**
		 * Metodo que permite determinar que hara el programa si cierto comando es precionado
		 * @param c El comando que activo la accion
		 * @param d El objeto de donde salio la accion
		 */
		public void commandAction(Command c, Displayable d) {
			// Si el comando es regresar, regresa al menu principal
			if (c == back){
				display.setCurrent(opciones);
			}
			// Si el boton de OK busca cual de las intrucciones fue precionada, se ponen las nuevas intrucciones
			// como actales y se regresa al menu principal
			else{
				instrucActual = todasInst[opciones1.getSelectedIndex()];
				inter.setInstrucciones(instrucActual);
				display.setCurrent(opciones);
			}
			
		}
		
	}
	
	/**Clase listener que permite crear codigo y ponerle nombre 
	 */
	private class CrearCodigoListener implements CommandListener{
		TextField dato; //Guarda el dato que se le pida al usuario
		StringItem error; //StringItem que permite mostrar un error cuando el usuario no ingrese la opcion correcta
		Form pedir; // Form que permite mostrarle algo al usuario
		int select; //Permite guardar el numero de comando seleccionado

		/**
		 * Metodo que permite determinar que hara el programa si cierto comando es precionado
		 * @param c El comando que activo la accion
		 * @param d El objeto de donde salio la accion
		 */
		public void commandAction(Command c, Displayable d) {
			int comando=-1;
			// Si se preciono el ok que se utiliza para pedir la cantidad de repeticiones
			// se muestra un error si el numero esta fuera del limite permitido y si esta bien
			// se inserta la intruccion y se regresa a la pantalla de crear
			if (c == okl){
				int repet=0;
				try{
					repet = Integer.parseInt(dato.getString());
				}
				catch (Exception e){
					if (espanol){ 
						error.setLabel("El numero de repeticiones debe estar entre 1 y 9");
					}
					else{
						error.setLabel("The number of repetitions has to be between 1 and 9");
					}
					
				}
				if (repet<1 | repet>9){
					if (espanol){
						error.setLabel("El numero de repeticiones debe estar entre 1 y 9");
					}
					else{
						error.setLabel("The number of repetitions has to be between 1 and 9");
					}
				}
				else{
					insertarInstruccion(select, repet);	
					actual = crear;
					display.setCurrent(actual);	
				}			
			}
			// Si se preciono el ok que se utiliza para ingresar el nombre deseado se guarda el nombre
			// y se regresa al menu principal
			else if (c == okb){
				nombres[totalInst] = dato.getString();
				totalInst++;
				actual = opciones;
				display.setCurrent(actual);							
			}
			else{
				// Busca cual de los comandos en el array fue el precionado
				for (int i = 0; i < 8; i++){
					if (comandos[i] == c)
						comando = i;
				}	
				// Si el comando es Regresar
				if (comando == 0){
					if (!actual.equals(pedir)){ // Se revisa que no este en la pantalla para pedir algun dato
						// Se revisa si el StringItem no esta vacio para pedir al usuario el nombre que le quiere dar al codigo
						if(!instrucciones.getText().equals("")){ 
							todasInst[totalInst]=instrucciones.getText()+"end";
							if (espanol){
								pedir = new Form("Peticion de nombre");
								dato = new TextField("Ingresa el nombre de tu codigo: ", "", 15, TextField.INITIAL_CAPS_WORD);
							}
							else{
								pedir = new Form("Name Request");
								dato = new TextField("Enter your codes name: ", "", 15, TextField.INITIAL_CAPS_WORD);					
							}
							pedir.addCommand(okb);
							pedir.addCommand(comandos[0]);
							pedir.append(dato);
							pedir.setCommandListener(this);	
							actual = pedir;							
						}
						else{ // Si el StringItem esta vacio regresa al menu principal
							actual = opciones;							
						}
					}
					else // Si esta en la pantalla para pedir algun dato regresa al menu de crear
						actual = crear;
					display.setCurrent(actual);			
				}
				// Si el comando es el de borrar se regresa a las instrucciones que habia creado anteriormente
				else if(comando == 1){
					if (instAgre != 0){
						instAgre--;
						instrucciones.setText(instAnt[instAgre]); // Se obtiene la instruccion anterior
						instAnt[instAgre] = null;
					}
				}
				// Si fue cualquiera de los comandos de intruccion
				else{
					//Si fue backward o froward, pide al usuario que ingrese la cantidad de repeticiones deseada
					if (comando == 2 | comando == 3){ 
						if (espanol){
							pedir = new Form("Pedir Cantidad (debe ser entre 1 y 9)");
							dato = new TextField("Ingresa la cantidad de repeticiones: ", "", 15, TextField.NUMERIC);
						}
						else{
							pedir = new Form("Request Repetitions (has to be between 1 and 9)");
							dato = new TextField("Enter the repetitions quantity: ", "", 15, TextField.NUMERIC);						
						}
						error = new StringItem("","");
						select = comando;
						pedir.addCommand(okl);
						pedir.addCommand(comandos[0]);
						pedir.setCommandListener(this);
						pedir.append(dato);
						pedir.append(error);
						actual = pedir;
						display.setCurrent(actual);
					}
					// Si fue otra instruccion se inserta la instruccion
					else
						insertarInstruccion(comando, 1);				
				}
				
			}
			
		}
		
	}
	

}